﻿using System.Reflection;

namespace AutoRevit.Entry.Application;

/// <summary>
/// 外部应用模块基类
/// </summary>
public abstract class ExternalModuleBase : IExternalModule
{
    /// <summary>
    /// 
    /// </summary>
    protected readonly IList<IExternalModule> Modules = [];

    /// <summary>
    /// 
    /// </summary>
    private readonly IList<Type> _moduleTypes = new List<Type>();

    /// <summary>
    /// 关闭
    /// </summary>
    /// <param name="application"></param>
    /// <returns></returns>
    protected virtual Result OnShutdown(UIControlledApplication application)
    {
        for (int i = 0; i < Modules.Count; i++)
        {
            var result = Modules[i].OnShutdown(application);

            if (result != Result.Succeeded)
            {
                return result;
            }
        }

        return Result.Succeeded;
    }

    /// <summary>
    /// 启动
    /// </summary>
    /// <param name="application"></param>
    /// <returns></returns>
    protected virtual Result OnStartup(UIControlledApplication application)
    {
        foreach (var item in _moduleTypes)
        {
            Modules.Add((IExternalModule)Activator.CreateInstance(item)!);
        }

        for (int i = 0; i < Modules.Count; i++)
        {
            var result = Modules[i].OnStartup(application);

            if (result != Result.Succeeded)
            {
                return result;
            }
        }

        return Result.Succeeded;
    }

    /// <inheritdoc/>
    Result IExternalModule.OnShutdown(UIControlledApplication application)
    {
        return OnShutdown(application);
    }

    /// <inheritdoc/>
    Result IExternalModule.OnStartup(UIControlledApplication application)
    {
        return OnStartup(application);
    }

    /// <summary>
    /// 添加外部应用模块
    /// </summary>
    /// <param name="externalModules"></param>
    protected virtual void AddModule(params IExternalModule[] externalModules)
    {
        if (externalModules is not null)
        {
            for (int i = 0; i < externalModules.Length; i++)
            {
                Modules.Add(externalModules[i]);
            }
        }
    }

    /// <summary>
    /// 添加外部应用模块
    /// </summary>
    /// <param name="assembliesToScan"></param>
    protected virtual void AddModuleClasses(params Assembly[] assembliesToScan)
    {
        AddModuleClasses(new HashSet<Assembly>(assembliesToScan));
    }

    /// <summary>
    /// 添加外部应用模块
    /// </summary>
    /// <param name="assembliesToScan"></param>
    protected virtual void AddModuleClasses(IEnumerable<Assembly> assembliesToScan)
    {
        if (assembliesToScan is null)
        {
            return;
        }

        assembliesToScan = new HashSet<Assembly>(assembliesToScan.Where((Assembly a) => !a.IsDynamic));

        Type[] openTypes = [typeof(IExternalModule)];

        //foreach (Type item in assembliesToScan.SelectMany((Assembly a) => from type in a.GetTypes()
        //                                                                  where type.IsClass && !type.IsAbstract && Array.Exists(openTypes, (Type openType) => type.GetGenericInterface(openType) != null)
        //                                                                  select type))
        //{
        //    _moduleTypes.Add(item);
        //}

        var appType = typeof(ExternalApplication);

        foreach (var assemblie in assembliesToScan)
        {
            foreach (var type in assemblie.GetTypes())
            {
                if (type.IsClass && !type.IsAbstract)
                {
                    if (Array.Exists(openTypes, openType => openType.IsAssignableFrom(type)))
                    {
                        if (!type.IsSubclassOf(appType))
                        {
                            _moduleTypes.Add(type);
                        }
                    }
                }
            }
        }
    }
}
